package io.xxx.eva.robot.send.limit;

import com.alibaba.fastjson.JSONObject;
import io.xxx.eva.robot.Robot;
import io.xxx.eva.task.PushRecord;
import io.xxx.eva.task.TaskMessage;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 消息条数限制
 */
@Slf4j
@Component
public class CommonMessageLimiter extends AbstractMessageLimiter {

    @Value("${per.minute.message.send.limit:40}")
    private Integer limitSize;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private EntityManager entityManager;

    @Override
    public void acquire(Robot robot, TaskMessage message) {
        Query nativeQuery = entityManager.createNativeQuery("""
                select count(*), max(updated_time)
                from push_record
                where robot_id = ?1 and task_id = ?2
                """, JSONObject.class);
        nativeQuery.setParameter(1, robot.getId());
        nativeQuery.setParameter(2, message.getTask().getId());
        nativeQuery.executeUpdate();
        @SuppressWarnings("unchecked")
        List<JSONObject> resultList = nativeQuery.getResultList();
        JSONObject o = resultList.get(0);

        PushRecord query = new PushRecord();
        query.setRobot(robot);
        query.setMessage(message);
        Example<PushRecord> example = Example.of(query);
        RScoredSortedSet<Integer> set = redissonClient.getScoredSortedSet("robot:" + robot.getId() + ":p1:text");
        long timestamp = set.firstScore().longValue();
        int count = set.first() + 1;
        if (count > limitSize) {
            long now = System.currentTimeMillis();
            long timeout = now - timestamp;
            set.add(now, 1);
            try {
                TimeUnit.MILLISECONDS.sleep(timeout);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            set.add(System.currentTimeMillis(), count + 1);
        }
    }
}
